home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / dpmigcc5.zip / RSX / SOURCE / FPU-EMU / REG_COMP.C < prev    next >
C/C++ Source or Header  |  1994-05-27  |  8KB  |  380 lines

  1. /*---------------------------------------------------------------------------+
  2.  |  reg_compare.c                                                            |
  3.  |                                                                           |
  4.  | Compare two floating point registers                                      |
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1994                                              |
  7.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  8.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12.  
  13. /*---------------------------------------------------------------------------+
  14.  | compare() is the core FPU_REG comparison function                         |
  15.  +---------------------------------------------------------------------------*/
  16.  
  17. #include "fpu_system.h"
  18. #include "exception.h"
  19. #include "fpu_emu.h"
  20. #include "control_w.h"
  21. #include "status_w.h"
  22.  
  23.  
  24. int compare(FPU_REG const *b)
  25. {
  26.   int diff;
  27.  
  28.   if ( FPU_st0_ptr->tag | b->tag )
  29.     {
  30.       if ( FPU_st0_ptr->tag == TW_Zero )
  31.     {
  32.       if ( b->tag == TW_Zero ) return COMP_A_eq_B;
  33.       if ( b->tag == TW_Valid )
  34.         {
  35.           return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  36. #ifdef DENORM_OPERAND
  37.         | ((b->exp <= EXP_UNDER) ?
  38.            COMP_Denormal : 0)
  39. #endif DENORM_OPERAND
  40.           ;
  41.         }
  42.     }
  43.       else if ( b->tag == TW_Zero )
  44.     {
  45.       if ( FPU_st0_ptr->tag == TW_Valid )
  46.         {
  47.           return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
  48.               : COMP_A_lt_B)
  49. #ifdef DENORM_OPERAND
  50.         | ((FPU_st0_ptr->exp <= EXP_UNDER )
  51.            ? COMP_Denormal : 0 )
  52. #endif DENORM_OPERAND
  53.           ;
  54.         }
  55.     }
  56.  
  57.       if ( FPU_st0_ptr->tag == TW_Infinity )
  58.     {
  59.       if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
  60.         {
  61.           return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
  62.               : COMP_A_lt_B)
  63. #ifdef DENORM_OPERAND
  64.           | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
  65.         COMP_Denormal : 0 )
  66. #endif DENORM_OPERAND
  67. ;
  68.         }
  69.       else if ( b->tag == TW_Infinity )
  70.         {
  71.           /* The 80486 book says that infinities can be equal! */
  72.           return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
  73.         ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
  74.         }
  75.       /* Fall through to the NaN code */
  76.     }
  77.       else if ( b->tag == TW_Infinity )
  78.     {
  79.       if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) )
  80.         {
  81.           return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  82. #ifdef DENORM_OPERAND
  83.         | (((FPU_st0_ptr->tag == TW_Valid)
  84.             && (FPU_st0_ptr->exp <= EXP_UNDER)) ?
  85.            COMP_Denormal : 0)
  86. #endif DENORM_OPERAND
  87.           ;
  88.         }
  89.       /* Fall through to the NaN code */
  90.     }
  91.  
  92.       /* The only possibility now should be that one of the arguments
  93.      is a NaN */
  94.       if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) )
  95.     {
  96.       if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
  97.           || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
  98.         /* At least one arg is a signaling NaN */
  99.         return COMP_No_Comp | COMP_SNaN | COMP_NaN;
  100.       else
  101.         /* Neither is a signaling NaN */
  102.         return COMP_No_Comp | COMP_NaN;
  103.     }
  104.       
  105.       EXCEPTION(EX_Invalid);
  106.     }
  107.   
  108. #ifdef PARANOID
  109.   if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  110.   if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
  111. #endif PARANOID
  112.  
  113.   
  114.   if (FPU_st0_ptr->sign != b->sign)
  115.     {
  116.       return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  117. #ifdef DENORM_OPERAND
  118.     |
  119.       ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
  120.        COMP_Denormal : 0)
  121. #endif DENORM_OPERAND
  122.         ;
  123.     }
  124.  
  125.   diff = FPU_st0_ptr->exp - b->exp;
  126.   if ( diff == 0 )
  127.     {
  128.       diff = FPU_st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
  129.                           identical */
  130.       if ( diff == 0 )
  131.     {
  132.     diff = FPU_st0_ptr->sigl > b->sigl;
  133.     if ( diff == 0 )
  134.       diff = -(FPU_st0_ptr->sigl < b->sigl);
  135.     }
  136.     }
  137.  
  138.   if ( diff > 0 )
  139.     {
  140.       return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
  141. #ifdef DENORM_OPERAND
  142.     |
  143.       ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
  144.        COMP_Denormal : 0)
  145. #endif DENORM_OPERAND
  146.         ;
  147.     }
  148.   if ( diff < 0 )
  149.     {
  150.       return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
  151. #ifdef DENORM_OPERAND
  152.     |
  153.       ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
  154.        COMP_Denormal : 0)
  155. #endif DENORM_OPERAND
  156.         ;
  157.     }
  158.  
  159.   return COMP_A_eq_B
  160. #ifdef DENORM_OPERAND
  161.     |
  162.       ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
  163.        COMP_Denormal : 0)
  164. #endif DENORM_OPERAND
  165.     ;
  166.  
  167. }
  168.  
  169.  
  170. /* This function requires that st(0) is not empty */
  171. int compare_st_data(void)
  172. {
  173.   int f, c;
  174.  
  175.   c = compare(&FPU_loaded_data);
  176.  
  177.   if (c & COMP_NaN)
  178.     {
  179.       EXCEPTION(EX_Invalid);
  180.       f = SW_C3 | SW_C2 | SW_C0;
  181.     }
  182.   else
  183.     switch (c & 7)
  184.       {
  185.       case COMP_A_lt_B:
  186.     f = SW_C0;
  187.     break;
  188.       case COMP_A_eq_B:
  189.     f = SW_C3;
  190.     break;
  191.       case COMP_A_gt_B:
  192.     f = 0;
  193.     break;
  194.       case COMP_No_Comp:
  195.     f = SW_C3 | SW_C2 | SW_C0;
  196.     break;
  197. #ifdef PARANOID
  198.       default:
  199.     EXCEPTION(EX_INTERNAL|0x121);
  200.     f = SW_C3 | SW_C2 | SW_C0;
  201.     break;
  202. #endif PARANOID
  203.       }
  204.   setcc(f);
  205.   if (c & COMP_Denormal)
  206.     {
  207.       return denormal_operand();
  208.     }
  209.   return 0;
  210. }
  211.  
  212.  
  213. static int compare_st_st(int nr)
  214. {
  215.   int f, c;
  216.  
  217.   if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
  218.     {
  219.       setcc(SW_C3 | SW_C2 | SW_C0);
  220.       /* Stack fault */
  221.       EXCEPTION(EX_StackUnder);
  222.       return !(control_word & CW_Invalid);
  223.     }
  224.  
  225.   c = compare(&st(nr));
  226.   if (c & COMP_NaN)
  227.     {
  228.       setcc(SW_C3 | SW_C2 | SW_C0);
  229.       EXCEPTION(EX_Invalid);
  230.       return !(control_word & CW_Invalid);
  231.     }
  232.   else
  233.     switch (c & 7)
  234.       {
  235.       case COMP_A_lt_B:
  236.     f = SW_C0;
  237.     break;
  238.       case COMP_A_eq_B:
  239.     f = SW_C3;
  240.     break;
  241.       case COMP_A_gt_B:
  242.     f = 0;
  243.     break;
  244.       case COMP_No_Comp:
  245.     f = SW_C3 | SW_C2 | SW_C0;
  246.     break;
  247. #ifdef PARANOID
  248.       default:
  249.     EXCEPTION(EX_INTERNAL|0x122);
  250.     f = SW_C3 | SW_C2 | SW_C0;
  251.     break;
  252. #endif PARANOID
  253.       }
  254.   setcc(f);
  255.   if (c & COMP_Denormal)
  256.     {
  257.       return denormal_operand();
  258.     }
  259.   return 0;
  260. }
  261.  
  262.  
  263. static int compare_u_st_st(int nr)
  264. {
  265.   int f, c;
  266.  
  267.   if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) )
  268.     {
  269.       setcc(SW_C3 | SW_C2 | SW_C0);
  270.       /* Stack fault */
  271.       EXCEPTION(EX_StackUnder);
  272.       return !(control_word & CW_Invalid);
  273.     }
  274.  
  275.   c = compare(&st(nr));
  276.   if (c & COMP_NaN)
  277.     {
  278.       setcc(SW_C3 | SW_C2 | SW_C0);
  279.       if (c & COMP_SNaN)       /* This is the only difference between
  280.                   un-ordered and ordinary comparisons */
  281.     {
  282.       EXCEPTION(EX_Invalid);
  283.       return !(control_word & CW_Invalid);
  284.     }
  285.       return 0;
  286.     }
  287.   else
  288.     switch (c & 7)
  289.       {
  290.       case COMP_A_lt_B:
  291.     f = SW_C0;
  292.     break;
  293.       case COMP_A_eq_B:
  294.     f = SW_C3;
  295.     break;
  296.       case COMP_A_gt_B:
  297.     f = 0;
  298.     break;
  299.       case COMP_No_Comp:
  300.     f = SW_C3 | SW_C2 | SW_C0;
  301.     break;
  302. #ifdef PARANOID
  303.       default:
  304.     EXCEPTION(EX_INTERNAL|0x123);
  305.     f = SW_C3 | SW_C2 | SW_C0;
  306.     break;
  307. #endif PARANOID
  308.       }
  309.   setcc(f);
  310.   if (c & COMP_Denormal)
  311.     {
  312.       return denormal_operand();
  313.     }
  314.   return 0;
  315. }
  316.  
  317. /*---------------------------------------------------------------------------*/
  318.  
  319. void fcom_st()
  320. {
  321.   /* fcom st(i) */
  322.   compare_st_st(FPU_rm);
  323. }
  324.  
  325.  
  326. void fcompst()
  327. {
  328.   /* fcomp st(i) */
  329.   if ( !compare_st_st(FPU_rm) )
  330.     pop();
  331. }
  332.  
  333.  
  334. void fcompp()
  335. {
  336.   /* fcompp */
  337.   if (FPU_rm != 1)
  338.     {
  339.       FPU_illegal();
  340.       return;
  341.     }
  342.   if ( !compare_st_st(1) )
  343.     {
  344.       pop(); FPU_st0_ptr = &st(0);
  345.       pop();
  346.     }
  347. }
  348.  
  349.  
  350. void fucom_()
  351. {
  352.   /* fucom st(i) */
  353.   compare_u_st_st(FPU_rm);
  354.  
  355. }
  356.  
  357.  
  358. void fucomp()
  359. {
  360.   /* fucomp st(i) */
  361.   if ( !compare_u_st_st(FPU_rm) )
  362.     pop();
  363. }
  364.  
  365.  
  366. void fucompp()
  367. {
  368.   /* fucompp */
  369.   if (FPU_rm == 1)
  370.     {
  371.       if ( !compare_u_st_st(1) )
  372.     {
  373.       pop(); FPU_st0_ptr = &st(0);
  374.       pop();
  375.     }
  376.     }
  377.   else
  378.     FPU_illegal();
  379. }
  380.